package org.example01.System1;

import java.io.*;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.*;

public class StudentManageSystem {
    ArrayList<Student> students = new ArrayList<>();

    public void addStudent(Student student) {
        try {
            if (student != null && isEmail(student)) {
                students.add(student);
            }
        } catch (Exception e) {
            System.out.println("添加失败" + e.getMessage());
            e.printStackTrace();
        }
    }

    public void updateStudent(int index, Student student) {
        try {
            if (index >= 1 && index < students.size()) {
                students.set(index - 1, student);
            } else {
                throw new IndexOutOfBoundsException("索引超出范围:" + index);
            }
        } catch (Exception e) {
            System.out.println("更新失败" + e.getMessage());
            e.printStackTrace();
        }
    }

    public void showAllStudent() {
        showAllStudent(students);
    }

    public void showAllStudent(Collection<Student> students) {
        int i = 1;
        try {
            for (Student s : students) {
                System.out.print(i++ + "   ");
                System.out.println(s);
            }
        } catch (Exception e) {
            System.out.println("显示学生信息时出错" + e.getMessage());
            e.printStackTrace();
        }
    }

    public void showStudentByID(String ID) {
        try {
            for (Student s : students) {
                if (s.getID().equals(ID)) {
                    System.out.println(s);
                    return;
                }
            }
            System.out.println("没有该学号的学生信息");
        } catch (NullPointerException e) {
            System.out.println("学生为空" + e.getMessage());
            e.printStackTrace();
        }
    }

    public Student findStudentWithHighScore(String subject) {
        try {
            return Collections.max(students, new Comparator<Student>() {
                public int compare(Student s1, Student s2) {
                    return findScoreBySubject(s1, subject) - findScoreBySubject(s2, subject);
                }
            });
        } catch (NoSuchElementException e) {
            System.out.println("没有学生信息" + e.getMessage());
            e.printStackTrace();
            return null;
        } catch (ClassCastException e) {
            System.out.println("不可比较" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    public Student findStudentWithLowScore(String subject) {
        try {
            return Collections.min(students, new Comparator<Student>() {
                public int compare(Student s1, Student s2) {
                    return findScoreBySubject(s1, subject) - findScoreBySubject(s2, subject);
                }
            });
        } catch (NoSuchElementException e) {
            System.out.println("没有学生信息" + e.getMessage());
            e.printStackTrace();
            return null;
        } catch (ClassCastException e) {
            System.out.println("不可比较" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    private int findScoreBySubject(Student student, String subject) {
        try {
            switch (subject) {
                case "语文" -> {
                    return student.getChineseScore();
                }
                case "数学" -> {
                    return student.getMathScore();
                }
                case "历史" -> {
                    if (student instanceof JuniorHighStudent) {
                        JuniorHighStudent juniorHighStudent = (JuniorHighStudent) student;
                        return juniorHighStudent.HistoryScore;
                    }
                }
                case "物理" -> {
                    if (student instanceof JuniorHighStudent) {
                        JuniorHighStudent juniorHighStudent = (JuniorHighStudent) student;
                        return juniorHighStudent.PhysicsScore;
                    }
                }
            }
            return 0;
        } catch (Exception e) {
            throw new RuntimeException("查找" + student + "的成绩时出错" + e);
        }

    }

    public double getAverageScoreBySubject(String subject) {
        int sum = 0;
        int count = 0;
        try {
            for (Student s : students) {
                if (s != null) {
                    sum += findScoreBySubject(s, subject);
                    count++;
                }
            }
            return count == 0 ? 0 : (double) sum / count;
        } catch (Exception e) {
            throw new RuntimeException("计算平均成绩时出错" + e);
        }
    }

    /*public void sortStudentByTotalScore() {
        TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
            public int compare(Student s1, Student s2) {
                return s2.getTotalScore() == s1.getTotalScore() ? (s2.getID().compareTo(s1.getID())) : s2.getTotalScore() > s1.getTotalScore() ? 1 : -1;
            }
        });
        treeSet.addAll(students);
        showAllStudent(treeSet);
    }*/
    public void sortStudentByTotalScore() {
        try {
            ArrayList<Student> students = this.students;
            students.sort(new Comparator<Student>() {
                public int compare(Student s1, Student s2) {
                    return s2.getTotalScore() - s1.getTotalScore();
                }
            });
            showAllStudent(students);
        } catch (Exception e) {
            System.out.println("排序失败" + e.getMessage());
            e.printStackTrace();
        }
    }

    public ArrayList<Student> getStudentsBeforeData(String date) {
        ArrayList<Student> students = new ArrayList<>();
        try {
            LocalDate localDate = LocalDate.parse(date);
            for (Student s : this.students) {
                if (s != null) {
                    if (s.getEnterDate().isBefore(localDate) || s.getEnterDate().isEqual(localDate)) {
                        students.add(s);
                    }
                }
            }
        } catch (DateTimeParseException e) {
            System.out.println("日期格式错误" + e.getMessage());
        } catch (Exception e) {
            throw new RuntimeException("获取指定日期之前入学的学生失败", e);
        }
        return students;
    }

    public ArrayList getStudentsAfterData(String date) {
        ArrayList<Student> students = new ArrayList<>();
        try {
            LocalDate localDate = LocalDate.parse(date);

            for (Student s : this.students) {
                if (s != null) {
                    if (s.getEnterDate().isAfter(localDate) || s.getEnterDate().isEqual(localDate)) {
                        students.add(s);
                    }
                }
            }
        } catch (DateTimeParseException e) {
            System.out.println("日期格式错误" + e.getMessage());
        } catch (Exception e) {
            throw new RuntimeException("获取指定日期之后入学的学生失败", e);
        }
        return students;
    }

    public boolean isEmail(Student student) {
        if (student == null || student.getEmail() == null) {
            throw new NullPointerException("学生或邮箱为空");
        } else {
            return student.getEmail().matches("\\w+@\\w+\\.\\w+");
        }
    }

    public Student randomStudent() {
        try {
            return students.get(new Random().nextInt(students.size()));
        } catch (Exception e) {
            System.out.println("随机失败" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    public Map<Integer, Integer> getScoreStatisticsBySubject(String subject) {
        HashMap<Integer, Integer> ScoreStatistics = new HashMap<>();
        try {
            for (Student s : students) {
                int score = findScoreBySubject(s, subject);
                if (ScoreStatistics.containsKey(score)) {
                    ScoreStatistics.put(score, ScoreStatistics.get(score) + 1);
                } else {
                    ScoreStatistics.put(score, 1);
                }
            }
        } catch (Exception e) {
            System.out.println("获取成绩统计失败" + e.getMessage());
            e.printStackTrace();
        }
        return ScoreStatistics;
    }

    public void uploadAvatar(Student student, String a1, String a2) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(a1));


        //对上传的头像进行重命名，确保在服务器的唯一性
        String fileName = new File(a1).getName();
        String fileExtensionName = fileName.substring(fileName.lastIndexOf("."));//获取文件拓展名

        String newFileName = UUID.randomUUID().toString() + fileExtensionName;//生成新的文件名
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(a2 + '/' + newFileName));
        int b;
        while ((b = bis.read()) != -1) {
            bos.write(b);
        }

        student.setAvatar(a2 + '/' + newFileName);

        bis.close();
        bos.close();
    }

    //从文件中读取学生信息
    public void localStudentFromFile(String fileName) {
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(StudentManageSystem.class.getClassLoader().getSystemResourceAsStream(fileName)));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                String[] Data = line.split("    ");
                String ID = Data[0];
                String name = Data[1];
                int ChineseScore = Integer.parseInt(Data[2]);
                int MathScore = Integer.parseInt(Data[3]);
                if (fileName.equals("小学生信息.txt")) {
                    LocalDate EnterDate = LocalDate.parse(Data[4]);
                    String Email = Data[5];

                    addStudent(new PrimaryStudent(ID, name, ChineseScore, MathScore, EnterDate, Email));
                } else if (fileName.equals("中学生信息.txt")) {
                    int HistoryScore = Integer.parseInt(Data[4]);
                    int PhysicsScore = Integer.parseInt(Data[5]);
                    LocalDate EnterDate = LocalDate.parse(Data[6]);
                    String Email = Data[7];
                    String studentStatus = Data[8];
                    addStudent(new JuniorHighStudent(ID, name, ChineseScore, MathScore, HistoryScore, PhysicsScore, EnterDate, Email, studentStatus));
                }
            }
        } catch (IOException e) {
            System.out.println("文件读取失败" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    System.out.println("文件关闭失败" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    //输出学生信息到文件中
    public void localStudentToFile(String fileName) {
        BufferedWriter bufferedWriter = null;
        try {
            bufferedWriter = new BufferedWriter(new FileWriter(fileName));
            for (Student s : students) {
                bufferedWriter.write(s.toString());
                bufferedWriter.newLine();
            }
            bufferedWriter.close();
        } catch (FileNotFoundException e) {
            System.out.println("文件未找到" + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("文件写入失败" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (bufferedWriter != null) {
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    System.out.println("文件关闭失败" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    public void sortStudentByTotalScoreAndToFile(String fileName) {
        BufferedWriter bufferedWriter = null;
        try {
            ArrayList<Student> students = this.students;
            students.sort(new Comparator<Student>() {
                public int compare(Student s1, Student s2) {
                    return s2.getTotalScore() - s1.getTotalScore();
                }
            });
            bufferedWriter = new BufferedWriter(new FileWriter(fileName));
            for (Student s : students) {
                bufferedWriter.write(s.toString());
                bufferedWriter.newLine();
            }
        } catch (IOException e) {
            System.out.println("文件写入失败" + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("排序失败" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (bufferedWriter != null) {
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    System.out.println("文件关闭失败" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    public Field getStudentFieldWithProperty(Student student, String propertyName) throws IllegalAccessException, NoSuchFieldException {
        Class<?> stu = student.getClass();
        Field f = null;
        while (stu != null) {
            try {
                f = stu.getDeclaredField(propertyName);
                break;
            } catch (NoSuchFieldException e) {
                stu = stu.getSuperclass();
            }
        }
        if (f == null) {
            throw new NoSuchFieldException("没有找到属性" + propertyName);
        }
        f.setAccessible(true);
        return f;
    }

    public void setStudentWithProperty(Student student, String propertyName, Object value) throws IllegalAccessException, NoSuchFieldException {
        //Class<Student> studentClass = Student.class;
        Field f = getStudentFieldWithProperty(student, propertyName);
        f.setAccessible(true);
        f.set(student, value);
    }

    public Object getStudentWithProperty(Student student, String propertyName) throws IllegalAccessException, NoSuchFieldException {
        Field f = getStudentFieldWithProperty(student, propertyName);
        return f.get(student);
    }
}
